2017-01-31 3 views
3

저는 C#으로 속도를 높이고 있습니다. 내 경험은 C++과 Java에 있습니다. 선언하고 일부 관련 필드를 초기화 할 때 "여러 가지 장소에서 동일한 코드 반복"을 줄이기 위해 사용할 수있는 트릭이 있는지 궁금합니다.C#에서 간결한 필드 초기화에 대한 팁

은 여기합니다 (UrhoSharp 3D 라이브러리를 사용) 할 싶습니다 어떤 사소한 예입니다 :

public class MyScene 
{ 
    Scene scene = new Scene(); 
    Node camera = scene.CreateChild("Camera"); 
    Node light = scene.CreateChild("Light"); 
    Node model = scene.CreateChild("Model"); 

    // etc 
} 

Node 필드 이니셜 라이저는 "비 정적을 참조 할 수 있기 때문에,이 컴파일되지 않습니다 필드 "scene. 가장 간단한 해결책은 될 것 같다 : 모두 추가 Node를 들어

public class MyScene2 
{ 
    Scene scene = new Scene(); 
    Node camera, light, model; 

    MyScene2() 
    { 
     camera = scene.CreateChild("Camera"); 
     light = scene.CreateChild("Light"); 
     model = scene.CreateChild("Model"); 
    } 

    // etc 
} 

, 는 내가 두 줄의 코드를 수정해야 할 코드 두 개의 추가 라인이 필요합니다. (편집 : Gusman의 제안에 따라 선언문을 한 줄로 접었습니다)이 광력을 만들기 위해 사용할 수있는 기술이 있습니까?

최근 버전의 C++에서 첫 번째 코드 조각이 작동합니다 - 필드는 엄격한 순서로 초기화되고 이전 필드를 참조 할 수 있습니다. Java에서는 외부 클래스에 scene을 넣을 수 있고 내부 클래스에 Node 필드가있어 참조 할 수 있지만 C#에는 내부 클래스와 동일한 개념이 없습니다. (물론 언어가 "더 좋다"는 말은 아니며 단지 다르고 그 언어에 익숙합니다.)

이 특정 예에서는 MySceneScene에서 상속 받았을 수 있습니다. 하지만 코드를 더 짧게 만들기 위해 상속을 도입하는 것에 매우 조심 스럽습니다! 그리고 모든 것이 직접 자식 인 scene이 아니라보다 복잡한 노드 트리가 필요할 수 있습니다. 그래서 필드 초기화 레벨에서 순수하게 수행 할 수있는 것이 있는지 궁금합니다.

+2

'노드 카메라, 광원, 모델; 코드 줄이기 비트 :) – Gusman

+0

Doh, yes! 좋은 생각, 조금 도움이됩니다. –

+1

저는 왜 당신이 생성자에서 많은 일을하는지에 대해 개인적으로 질문 할 것입니다. 어쩌면 당신은 장면을위한 자식 노드를 설정하는 MySceneFactory를 필요로하고, 그 각각의 필드 값을 MyScene 생성자에 주입 할 것입니다. 코드 라인이 늘어나지 만 우려 사항이 더 잘 분리됩니다. – StriplingWarrior

답변

-1

다음은 중첩 된 클래스를 사용하여 원하는 것을 얻는 예제입니다.

public class ShinyClass 
{ 
    class InnerVar 
    { 
     public static Random r = new Random(); 
    } 

    decimal d1 = InnerVar.r.Next(); 
    decimal d2 = InnerVar.r.Next(); 
    decimal d3 = InnerVar.r.Next(); 

    public override string ToString() 
    { 
     return d1 + " " + d2 + " " + d3; 
    } 
} 

업데이트 : 여기 잡았다 순간이있다. 내부 클래스의 변수 값을 변경하면 정적 속성이 모든 ShinyClass 객체에 영향을줍니다. 예를 들어, 어딘가에 널을 만들고 다른 메소드가 다른 객체에서 그것을 사용하려한다면, 이것은 작동하지 않을 것입니다. 그래서 당신은 위의 내 ShinyClass이 뭔가를 추가하는 경우 :

public void KillRandom() 
{ 
    InnerVar.r = null; 
} 

public int UseVar() 
{ 
    return InnerVar.r.Next(); 
} 

그리고 당신은 시도와 같은 것을 수행

var s = new ShinyClass().ToString(); 

new ShinyClass().KillRandom(); 

var e = new ShinyClass().UseVar(); 

s 유효한 결과가 될 것입니다,하지만 발생합니다 e을 얻으려고 노력 NullReferenceException입니다. 이 경우이 방법은 도움이되지 않습니다.

+0

'정적'은 조금 두렵습니다! 정확히 언제 초기화되는지에 대한 보증이 있습니까? 'InnerVar'에 대한 최초의 언급? –

+0

정적이 초기화 될 때 좋은 링크가 있습니다 -> http://stackoverflow.com/a/3681278/1193647. C#은 처음 사용하기 전에 변수를 초기화합니다 (아마도 100 % 정확하지는 않습니다). – Kolichikov

+0

이것이 왜 downvoted 이유에 대해 궁금합니다 – Kolichikov

1

편집 : 속성 및 expression-bodied members을 사용하여 원하는 간결 성을 얻을 수 있습니다.

sealed class MyScene2 
{ 
    public Scene scene => new Scene(); 
    public Node camera => scene.CreateChild("Camera"); 
    public Node light => scene.CreateChild("Light"); 
    public Node model => scene.CreateChild("Model"); 
} 

그러나 그의 코드는 속성에 액세스 할 때마다 CreateChild()을 호출합니다.

나는 한 시간 동안 필드의 초기화가 C# 7의 튜플 사용하고 지금까지 가지고 올 수 있었던 가장 간결 :

한 줄 이상입니다
public class MyScene 
{ 
    static (Scene, Node, Node, Node) f(Scene scene) 
    { 
     return (scene, scene.CreateChild("Camera"), scene.CreateChild("Light"), scene.CreateChild("Model")); 
    } 
    readonly (Scene scene, Node camera, Node light, Node model) t2 = f(new Scene()); 
}; 

...

+0

이것은 말더듬을 증가시키는 것 같습니다 - "카메라"(또는 "c")는 이제 3 개의 다른 라인에서 6 번 사용됩니다. –

+1

@IainMerrick 표현식 바디 멤버로 초기화 된 속성을 사용하여 새 코드로 답변을 업데이트했습니다. –

+0

아, 깔끔한! 그것이 제가 배우고 싶은 바로 그 종류의 것입니다. 속성에 액세스 할 때마다 해당 식을 실행하는 것처럼 들리는가? 그렇다면 문제가 명시된 바와 같이 작동하지 않습니다. 멤버 변수는 한 번만 초기화해야합니다. –

0

하는 경우를 간결성은 당신의 주요 관심사이고 당신은 왜 이런 일하지 같은 방식으로 민간 분야의 무리를 초기화 할 수있을 것으로 예상이 허용

public class Scenery { 
    Dictionary<String, Node> children = new Dictionary<String, Node> { 
       {"Camera", null}, {"Light", null}, {"Model", null}}; 

    Scene scene = new Scene(); 

    public Scenery() { 
     foreach (var s in children.Keys) { 
      children[s] = scene.CreateChild(s); 
     } 
    } 
} 

를 사용하면 쉽게 광고에 필요에 따라 필드를 뺍니다. 흥미롭게도

+0

그러면 나중에 노드에 액세스하기가 더 어려워집니다. 원하는 노드가 포함 된 명명 된 필드를 갖는 대신 사전에서 계속 가져와야합니다. –

+0

사실이지만 사전은 매우 빠르며 의도는 항상 명확합니다 (예 : children [ "Camera"]. DoSomething()). 정말 귀찮다면 getters 'Node Camera {get {return children [ "Camera"]; }} ',하지만 그건 간결함에 반하는 것입니다. – Dweeberly

1

, C++/CLI 지원은 "간결"구문을 수행합니다

ref struct MyScene 
{ 
    Scene^ scene = gcnew Scene(); 
    Node^ camera = scene->CreateChild("Camera"); 
    Node^ light = scene->CreateChild("Light"); 
    Node^ model = scene->CreateChild("Model"); 
}; 

당신도 (C 번호에서 "readonly") initonly을 추가 할 수 있습니다 각 필드에 있습니다.